package com.mokylin.dbschema.util;

import com.mokylin.dbschema.cache.Cache;
import com.mokylin.dbschema.cache.Element;
import com.mokylin.dbschema.cache.ElementValueLoader;
import com.mokylin.dbschema.cache.ValueLoader;
import com.mokylin.dbschema.config.ConfigInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 读配置数据库的配置表：
 * @author Li Zhao
 * @since 2016/5/13.
 */
public class DbConfigUtils {

    private static final Logger LOG = LoggerFactory.getLogger(DBUtils.class);

    private static Connection connection;

    private static void init(){
        String jdbcUrl = String.format("jdbc:mysql://%1$s:%2$s/%3$s", ConfigInfo.getConfigDbHost(), ConfigInfo.getConfigDbPort(), ConfigInfo.getConfigDbName());
        try {
            if (connection != null && !connection.isClosed()) {
                //            throw new IllegalStateException("数据库已经初始化");
                return;
            }
        } catch (SQLException e) {
            LOG.error(e.getMessage());
        }
        try {
            Class.forName(ConfigInfo.getJdbcDriver());
            connection = DriverManager.getConnection(
                    jdbcUrl,
                    ConfigInfo.getConfigDbUsername(),
                    ConfigInfo.getConfigDbPassword());
        } catch (Exception e) {
            LOG.error("init config db connection error,"+e.getMessage(), e);
        }
    }
    private static Connection getConn() {
        try {
            if(connection==null || connection.isClosed()){
                init();
            }
        } catch (SQLException e) {
            LOG.error(e.getMessage(),e);
        }
        return connection;
    }


    private static void closeConnection() {
        try {
            if (connection!=null && !connection.isClosed()) connection.close();
        } catch (SQLException e) {
            LOG.error(e.getMessage(), e);
        }
    }


    private static Cache<String, String> cache = new Cache<>(new ElementValueLoader<String,Element<String,String>,String>() {
        @Override
        public Element<String,String> load(String s) {
            return DbConfigUtils.loadValue(s);
        }
    });

    public static Element<String, String> loadValue(String key) {
        PreparedStatement stmt = null;
        Connection conn = null;
        try {
            conn = getConn();
            stmt = conn.prepareStatement("SELECT c_value,c_expire_seconds FROM tb_config WHERE c_appid=? AND c_key=?");
            stmt.setString(1, ConfigInfo.getAppId());
            stmt.setString(2, key);
            ResultSet rs = stmt.executeQuery();
            if (rs.next()) {
                String c_value = rs.getString("c_value");
                long expire = rs.getLong("c_expire_time");
                if (expire < 1) {
                    expire = ConfigInfo.getDefaultCacheExpireSeconds();
                }
                return new Element<>(key, c_value, TimeUnit.SECONDS.toNanos(expire));
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        } finally {
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static boolean initialized(){
        try {
            return connection!=null && !connection.isClosed();
        } catch (SQLException e) {
            return false;
        }
    }
    public static void close(){
        closeConnection();
    }

    public static String getConfig(String key){
            return cache.get(key);
    }

    public static Map<String,String> asMap(){
        ConcurrentHashMap<String, Element<String, String>> map = cache.asMap();
        Map<String,String> res = new HashMap<>();
        map.forEach((k,e)-> res.put(k,e.getValue()));
        return res;
    }

    public static void clearUp(){
        cache.cleanUp();
    }
}
